#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>

using namespace std;


//按序打印
//https://leetcode.cn/problems/print-in-order/
class Foo {
public:
    Foo() 
        :flag(0)
    {}

    void first(function<void()> printFirst) {
        
        // printFirst() outputs "first". Do not change or remove this line.
        unique_lock<mutex> ul(m);
        cv.wait(ul,[&]{ return flag == 0; });
        printFirst();
        ++flag;
        cv.notify_all();
    }

    void second(function<void()> printSecond) {
        
        // printSecond() outputs "second". Do not change or remove this line.
        unique_lock<mutex> ul(m);
        cv.wait(ul,[&]{ return flag == 1; });
        printSecond();
        ++flag;
        cv.notify_all();
    }

    void third(function<void()> printThird) {
        
        // printThird() outputs "third". Do not change or remove this line.
        unique_lock<mutex> ul(m);
        cv.wait(ul,[&]{ return flag == 2; });
        printThird();
        cv.notify_all();
        flag = 0;
    }

private:
    mutex m;
    condition_variable cv;
    int flag;
};



//H2O 生成
//https://leetcode.cn/problems/building-h2o/submissions/
class H2O {
public:
    H2O() 
        :flag(2)
    {}

    void hydrogen(function<void()> releaseHydrogen) {
        
        // releaseHydrogen() outputs "H". Do not change or remove this line.
        unique_lock<mutex> ul(m);
        cv.wait(ul,[&]{return flag<2;});
        releaseHydrogen();
        ++flag;
        cv.notify_all();
    }

    void oxygen(function<void()> releaseOxygen) {
        
        // releaseOxygen() outputs "O". Do not change or remove this line.
        unique_lock<mutex> ul(m);
        cv.wait(ul,[&]{return flag == 2;});
        releaseOxygen();
        flag = 0;
        cv.notify_all();
    }

    mutex m; //互斥锁
    condition_variable cv; //条件变量
    int flag; //生产标志 true表示生产2个H false表示生产1个O 
};
